import { SemVer } from 'semver';
import { ConfigurationTarget, Disposable, Event, Uri } from 'vscode';
import { FileChangeType } from '../common/platform/fileSystemWatcher';
import { Resource } from '../common/types';
import { EQEnvSource } from '../eqEnvironments/base/info';
import { EQLocatorQuery } from '../eqEnvironments/base/locator';
import { CondaEnvironmentInfo } from '../eqEnvironments/common/environmentManagers/conda';
import { EnvironmentType, EQEnvironment } from '../eqEnvironments/info';

export type EQEnvironmentsChangedEvent = {
    type?: FileChangeType;
    resource?: Uri;
    old?: EQEnvironment;
    new?: EQEnvironment | undefined;
};

export const IInterpreterService = Symbol('IInterpreterService');
export interface IInterpreterService {
    readonly onRefreshStart: Event<void>;
    triggerRefresh(query?: EQLocatorQuery & { clearCache?: boolean }, trigger?: 'auto' | 'ui'): Promise<void>;
    readonly refreshPromise: Promise<void> | undefined;
    readonly onDidChangeInterpreters: Event<EQEnvironmentsChangedEvent>;
    onDidChangeInterpreterConfiguration: Event<Uri | undefined>;
    onDidChangeInterpreter: Event<void>;
    onDidChangeInterpreterInformation: Event<EQEnvironment>;
    hasInterpreters(filter?: (e: EQEnvironment) => Promise<boolean>): Promise<boolean>;
    getInterpreters(resource?: Uri): EQEnvironment[];
    getAllInterpreters(resource?: Uri): Promise<EQEnvironment[]>;
    getActiveInterpreter(resource?: Uri): Promise<EQEnvironment | undefined>;
    getInterpreterDetails(eqthonPath: string, resoure?: Uri): Promise<undefined | EQEnvironment>;
    refresh(resource: Resource): Promise<void>;
    initialize(): void;
}


export const IComponentAdapter = Symbol('IComponentAdapter');
export interface IComponentAdapter {
    readonly onRefreshStart: Event<void>;
    triggerRefresh(query?: EQLocatorQuery & { clearCache?: boolean }, trigger?: 'auto' | 'ui'): Promise<void>;
    readonly refreshPromise: Promise<void> | undefined;
    readonly onChanged: Event<EQEnvironmentsChangedEvent>;
    // VirtualEnvPrompt
    onDidCreate(resource: Resource, callback: () => void): Disposable;
    // IInterpreterLocatorService
    hasInterpreters(filter?: (e: EQEnvironment) => Promise<boolean>): Promise<boolean>;
    getInterpreters(resource?: Uri, source?: EQEnvSource[]): EQEnvironment[];

    // WorkspaceVirtualEnvInterpretersAutoSelectionRule
    getWorkspaceVirtualEnvInterpreters(
        resource: Uri,
        options?: { ignoreCache?: boolean },
    ): Promise<EQEnvironment[]>;

    // IInterpreterService
    getInterpreterDetails(eqPath: string): Promise<EQEnvironment | undefined>;

    // IInterpreterHelper
    // Undefined is expected on this API, if the environment info retrieval fails.
    getInterpreterInformation(eqPath: string): Promise<Partial<EQEnvironment> | undefined>;

    isMacDefaultEQPath(eqPath: string): Promise<boolean>;

    // ICondaService
    isCondaEnvironment(interpreterPath: string): Promise<boolean>;
    // Undefined is expected on this API, if the environment is not conda env.
    getCondaEnvironment(interpreterPath: string): Promise<CondaEnvironmentInfo | undefined>;

    isWindowsStoreInterpreter(eqPath: string): Promise<boolean>;
}
export const IInterpreterStatusbarVisibilityFilter = Symbol('IInterpreterStatusbarVisibilityFilter');
export interface IInterpreterStatusbarVisibilityFilter {
    readonly changed?: Event<void>;
    readonly hidden: boolean;
}
export const IInterpreterDisplay = Symbol('IInterpreterDisplay');
export interface IInterpreterDisplay {
    refresh(resource?: Uri): Promise<void>;
    registerVisibilityFilter(filter: IInterpreterStatusbarVisibilityFilter): void;
}

export type WorkspaceEQPath = {
    folderUri: Uri;
    configTarget: ConfigurationTarget.Workspace | ConfigurationTarget.WorkspaceFolder;
};

export const IInterpreterHelper = Symbol('IInterpreterHelper');
export interface IInterpreterHelper {
    getActiveWorkspaceUri(resource: Resource): WorkspaceEQPath | undefined;
    getInterpreterInformation(eqPath: string): Promise<undefined | Partial<EQEnvironment>>;
    isMacDefaultEQPath(eqPath: string): Promise<boolean>;
    getInterpreterTypeDisplayName(interpreterType: EnvironmentType): string | undefined;
    getBestInterpreter(interpreters?: EQEnvironment[]): EQEnvironment | undefined;
}

export const ICondaService = Symbol('ICondaService');
/**
 * Interface carries the properties which are not available via the discovery component interface.
 */
export interface ICondaService {
    getCondaFile(forShellExecution?: boolean): Promise<string>;
    isCondaAvailable(): Promise<boolean>;
    getCondaVersion(): Promise<SemVer | undefined>;
    getInterpreterPathForEnvironment(condaEnv: CondaEnvironmentInfo): Promise<string | undefined>;
    getCondaFileFromInterpreter(interpreterPath?: string, envName?: string): Promise<string | undefined>;
}